require("Container")
require("Door")

Location = class("Location", Container)

---

function Location:initialize(name, type)

	if not type 
	then
		type = "Location"
	end
	
	Container.initialize(self, name, type)
	
	self:registerEntityType("Location")				-- we register Location type to insure that sub class with their own type are also register as Locations	

	self.doorsBetweenContainedLocations = {}
	self.doorsToNeighborhood = {}
	self.doorsToContainedLocations = {}
	self.doorsToContainingLocations = {}
	self.lastPropagationBeat = -1
end  

---

function Location:addLocation(name, type)

	return self:addSubContainer( Location:new(name, type) )
end

---

function Location:addDoorToContainedLocation(containedLocation, closedAndLocked)

	local doorName = self.name .. "<->" .. containedLocation.name
	
	Door:new(
		doorName, 
		self, 
		containedLocation, 
		closedAndLocked
	)
	return self.doorsBetweenContainedLocations[doorName]
end

---

function Location:addDoorBetweenContainedLocations(location1, location2, closedAndLocked)

	local doorName = location1.name .. "<->" .. location2.name
	
	Door:new(
		doorName, 
		location1, 
		location2, 
		closedAndLocked
	)
	return self.doorsBetweenContainedLocations[doorName]
end

---

function Location:addDoorToNeighborhood(door)

	self.doorsToNeighborhood[door.name] = door
end

---

function Location:getDoors(excludeDoorsToContainingLocations)

	local doors = {}
	
	for doorName, door in pairs(self.doorsToNeighborhood) 
	do
		doors[doorName] = door
	end
	
	for doorName, door in pairs(self.doorsToContainedLocations) 
	do
		doors[doorName] = door
	end
	
	if not excludeDoorsToContainingLocations 
	then
		for doorName, door in pairs(self.doorsToContainingLocations) 
		do
			doors[doorName] = door
		end
	end
	
	return doors
end

---

function Location:getAccessibleLocations(onlyUseCollapsedKeys, recursiveCall)

	gLogger:enterGroup("Get all accessible locations from : " .. self.name, true)
	

	-- prevent recursivity loops
	
	if not recursiveCall 
	then
		gLogger:log("Clear recursivity loop prevention for location " .. self.name)
		
		Location.accessibleLocations = {}
	end
	
	if not Location.accessibleLocations[self.name] 
	then
		Location.accessibleLocations[self.name] = self
		
		
		-- check connected locations
		
		for doorName, door in pairs(self:getDoors()) 
		do
			gLogger:log("Check connected location throught Door : " .. doorName)
		
			if 
				(
					door:isEnabled() or								-- we consider closed non yet collapsed doors with a lock
					door:isOpenableFromThisSide(self, onlyUseCollapsedKeys)
				)
			then			
				door:getOtherSide(self):getAccessibleLocations(onlyUseCollapsedKeys, true)
			end
		end
	end
		
	gLogger:leaveGroup()
		
	return Location.accessibleLocations
end

---

function Location:getLinksToPropagateObservation()

	return self.doorsToContainedLocations
end

---

function Location:getLinksToObserve()

	return self.doorsToNeighborhood
end